package com.slmxz.tms.core.service;

import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.slmxz.tms.common.component.RedisService;
import com.slmxz.tms.common.constant.SystemConstants;
import com.slmxz.tms.common.util.DateUtils;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 用于创建主键的服务接口
 * @Author：albert
 * @Date：2025/7/13 21:05
 */
public interface PrimaryKeySerivce<T> {
    ReentrantLock lock = new ReentrantLock();

    default Long getId() throws Exception {
        //根据yyMMdd获取当天的日期字符串
        String localDate = DateUtils.formatLocalDate();
        // 通过反射获取泛型参数类型
        Type[] types = this.getClass().getGenericInterfaces();
        if (types.length == 0) {
            return null;
        }
        for (Type genericSuperclass : types) {
            if(genericSuperclass instanceof ParameterizedType parameterizedType){
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
                if (actualTypeArguments.length == 0) {
                    continue;
                }
                for (Type actualTypeArgument : actualTypeArguments) {
                    Class<T> clazz = (Class<T>) actualTypeArgument;
                    // 获取 T 上的 TableName 注解
                    TableName tableName = clazz.getAnnotation(TableName.class);
                    if(tableName == null){
                        continue;
                    }
                    //组装redis中不同数据库表递增值的key
                    String tableIdKey = tableName.value() + localDate;
                    //如果在500ms内获取锁失败,则放弃继续加锁
                    if (lock.tryLock(SystemConstants.TRY_LOCK_TIMEOUT, TimeUnit.MILLISECONDS)) {
                        try {
                            //通过redis的自增长获取递增值
                            long incrVal = RedisService.incr(tableIdKey,1);
                            if(incrVal == 1L){
                                //每天初次获取值的时候
                                RedisService.expire(tableIdKey,2 * 24 * 60 * 60); //当前创建主键的key只保存2天
                            }
                            //组合成指定数据库表当天唯一的主键
                            return Long.parseLong(localDate + incrVal);
                        } finally {
                            lock.unlock();
                        }
                    }
                }
            }
        }
        return null;
    }
}
